package com.geostar.core.dataset.impl.dataset.mongo;

import com.geostar.core.common.jdbc.DBConnectionManager;
import com.geostar.core.dataset.*;
import com.geostar.core.dataset.filter.*;
import com.geostar.core.dataset.impl.BaseFeature;
import com.geostar.core.dataset.impl.dataset.FeatureDataLoader;
import com.geostar.core.dataset.impl.dataset.cursor.MongoFeatureCursor;
import com.geostar.core.dataset.info.IDataSetInfo;
import com.geostar.core.dataset.info.impl.VectorDataSetInfo;
import com.geostar.core.exception.DataSetException;
import com.geostar.core.exception.config.TextCodesConst;
import com.geostar.core.geom.GeoByteWriter;
import com.geostar.core.geom.GeoEnvelope;
import com.geostar.core.geom.GeoGeometry;
import com.geostar.core.geom.GeoGeometryFactory;
import com.geostar.core.spatialreference.CoordRefSystem;
import com.geostar.core.spatialreference.ICoordRefSystem;
import com.geostar.core.spatialreference.SpatialRefUtil;
import com.geostar.core.util.GUID64Utils;
import com.geostar.core.util.ObjectCloser;
import com.geostar.core.util.StringUtils;
import com.geostar.kernel.GsBox;
import com.geostar.kernel.GsSpatialReference;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;
import mongodb.conn.MongoExecutor;
import mongodb.jdbc.MongoArray;
import mongodb.jdbc.MongoConnection;
import org.apache.commons.dbcp.DelegatingConnection;
import org.bson.types.Binary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.*;


/**
 * MongoDB原始矢量数据集
 */
public class MongoVectorDataSet implements IFeatureDataSet, IFeatureWriter, IFeatureFastWriter {

    private static Logger log = LoggerFactory.getLogger(MongoVectorDataSet.class);

    /**
     * wanen2015.5.26 访问控制改成protected,子类需要复用
     */
    protected boolean _change = false;

    /**
     * wanen2015.5.26 访问控制改成protected,子类需要复用
     */
    protected double[] _referenceExtent = new double[]{-180, -90, 180, 90};

    /**
     * 当前数据集的数据源信息
     */
    private DataSourceInfo dsInfo = null;

    /**
     * 连接池管理工具 wanen2015.5.26子类需要复用
     */
    protected DBConnectionManager dbcManager = null;

    /**
     * 当前数据的连接池名称，采用文件的绝对路径标示 wanen2015.5.26子类需要复用
     */
    protected String poolName = null;

    // String dbName = null;

    /**
     * 数据名称
     */
    String dataName = null;

    private SpatialRelationType spatialOperation = SpatialRelationType.SPATIAL_RELATION_INTERSECTS;

    /**
     * 数据元信息 wanen2015.5.26子类需要复用
     */
    protected VectorDataSetInfo dataInfo = new VectorDataSetInfo();

    /**
     * 标示Geometry数据存储字节序，0表示高字节序，1表示低字节序 wanen2015.5.26 访问控制改成protected,子类需要复用
     */
    protected int endian = 0;

    /**
     * 保存数据的表名称，三维地名数据使用的表与普通矢量数据有区别
     */
    // private String dataTableName = "datatable";

    /**
     * 当前数据的所有属性字段名称 wanen2015.5.26子类需要复用
     */
    protected List<String> attributes = new ArrayList<String>();

    /**
     * 将GeoGeometry对象转换为内存块存储结构的byte数组 工具类
     */
    private GeoByteWriter writer = new GeoByteWriter();

    /**
     * 属性名称常量：数据集名称
     */
    public final static String META_KEY_NAME = "Name";

    /**
     * 属性名称常量：数据集别名
     */
    public final static String META_KEY_ALIASNAME = "AliasName";

    /**
     * 属性名称常量：编码类型
     */
    public final static String META_KEY_ENDIAN = "Endian";

    /**
     * 属性名称常量：EPSG号
     */
    public final static String META_KEY_EPSG = "EPSG";

    /**
     * 属性名称常量：空间参考
     */
    public final static String META_KEY_SPATIALREFERENCE = "SpatialReference";

    /**
     * 属性名称常量：注记数据标识
     */
    public final static String META_KEY_FEATURETYPE = "FeatureType";

    /**
     * 属性名称常量：数据集的几何类型
     */
    public final static String META_KEY_GEOMETRYTYPE = "GeometryType";

    /**
     * 属性名称常量：数据集的比例尺
     */
    public final static String META_KEY_SCALE = "Scale";

    /**
     * 属性名称常量：数据范围的最小X坐标
     */
    public final static String META_KEY_XMIN = "XMin";

    /**
     * 属性名称常量：数据范围的最大X坐标
     */
    public final static String META_KEY_XMAX = "XMax";

    /**
     * 属性名称常量：数据范围的最小Y坐标
     */
    public final static String META_KEY_YMIN = "YMin";

    /**
     * 属性名称常量：数据范围的最大Y坐标
     */
    public final static String META_KEY_YMAX = "YMax";

    /**
     * 属性名称常量：X方向容差
     */
    public final static String META_KEY_XTOLERANCE = "XTolerance";

    /**
     * 属性名称常量：Y方向容差
     */
    public final static String META_KEY_YTOLERANCE = "YTolerance";

    protected String tableName = null;

    // 20131008.1 增加预加载缓存数据集
    /**
     * 预加载缓存数据集
     */
    private FeatureDataLoader cacheDataSet = null;

    protected String wtfsDisplayField = null;

    /**
     * 新增featuretype字段，适配mongo新的类型 默认使用simple，此字段不对外开放，将get方法设为私有
     */
    private String featureType = null;

    /**
     * 构造方法
     *
     * @param dsInfo   数据源信息对象
     * @param dataBase 数据库对象
     */
    public MongoVectorDataSet(DataSourceInfo dsInfo, IDataBase dataBase) {
        this.dsInfo = dsInfo;
        ConnectionInfo connInfo = dsInfo.getConnectionInfo();
        try {
            // 获取连接池管理对象
            dbcManager = DBConnectionManager.getInstance();
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
        }
        dataName = dsInfo.getDataName();
        poolName = connInfo.getPoolName();
        if (null == poolName || "".equals(poolName)) {
            poolName = connInfo.getAddress() + "_" + connInfo.getUsername();
        }
        // 初始化读取元信息
        init();
    }

    /**
     * 初始化方法
     */
    @Override
    public void init() {
        Connection conn = dbcManager.getConnection(poolName);
        if (null == conn) {
            Object[] args = {poolName};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_CONNECTION_NULL, args);
        }
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            dataInfo.setDataName(dataName);

            String sql = "SELECT * FROM SPATIAL_OBJECT_CLASSES WHERE Name=?";
            //针对 三维地名数据查询增加表名拼接逻辑
            if (this.dsInfo != null && (this.dsInfo.getDataType() == DataType.TILE_PLN)) {
                String tmpSql = "SELECT * FROM TAB_WTFSMetaTable WHERE WTFS_POIDATASETNAME=?";
                stmt = conn.prepareStatement(tmpSql);
                stmt.setString(1,dataName);
                rs = stmt.executeQuery();
                String wtfs_classname = dataName;
                while (rs.next()) {
                    wtfs_classname = rs.getString("WTFS_CLASSNAME");
                    this.wtfsDisplayField = rs.getString("WTFS_DISPLAY_FIELD");
                }
                rs.close();
                stmt.close();
                stmt = conn.prepareStatement(sql);
                stmt.setString(1,wtfs_classname);
            }else{
                stmt = conn.prepareStatement(sql);
                stmt.setString(1,dataName);
            }
            //针对 三维地名数据查询增加表名拼接逻辑 end
            log.debug(String.format("[SQL] %s", sql));
            rs = stmt.executeQuery();
            if (null == rs) {
                throw new Exception("元表查询返回空结果集！");
            }

            HashMap<String, String> metainfo = new HashMap<String, String>();
            while (rs.next()) {
                tableName = rs.getString("TableName");
                // String dataName =
                // resultset.getString(MongoVectorDataSet.META_KEY_NAME);
                String dataAliasName = rs
                        .getString(MongoVectorDataSet.META_KEY_ALIASNAME);
                endian = 1;// Integer.valueOf(metainfo.get(MongoVectorDataSet.META_KEY_ENDIAN));
                String epsgNumber = "0";// String.valueOf(metainfo.get(MongoVectorDataSet.META_KEY_EPSG));
                String wktStr = rs.getString(MongoVectorDataSet.META_KEY_SPATIALREFERENCE);
                featureType = rs.getString(MongoVectorDataSet.META_KEY_FEATURETYPE);
                boolean isAnnotation = true;
                if("Simple".equals(featureType) || "eSimpleFeature".equals(featureType)){
                    isAnnotation = false;
                }

                String gType = rs.getString(MongoVectorDataSet.META_KEY_GEOMETRYTYPE);
                gType = gType.toUpperCase();

                GeometryType geometryType;
                if ("ANNOTATION".equals(gType)) {
                    geometryType = GeometryType.ANNOTATION;
                } else if ("POLYGON".equals(gType)) {
                    geometryType = GeometryType.POLYGON;
                } else if ("POLYLINE".equals(gType)) {
                    geometryType = GeometryType.LINE;
                } else if ("POINT".equals(gType)) {
                    geometryType = GeometryType.POINT;
                } else {
                    geometryType = GeometryType.UNKNOWN;
                }

                String tmps = metainfo.get(MongoVectorDataSet.META_KEY_SCALE);

                int scale = 10000;
                if (null != tmps) {
                    try {
                        scale = Integer.valueOf(tmps);
                    } catch (Exception ex) {
                        scale = 10000;
                    }
                }

                // double minX = Double.parseDouble(metainfo.get(
                // MongoVectorDataSet.META_KEY_XMIN).toString());
                tmps = metainfo.get(MongoVectorDataSet.META_KEY_XMIN);
                double minX = 0;
                if (null != tmps) {
                    try {
                        minX = Double.parseDouble(tmps);
                    } catch (Exception ex) {
                        minX = 0;
                    }
                }

                // double maxX = Double.parseDouble(metainfo.get(
                // MongoVectorDataSet.META_KEY_XMAX).toString());
                tmps = metainfo.get(MongoVectorDataSet.META_KEY_XMAX);
                double maxX = -1;
                if (null != tmps) {
                    try {
                        maxX = Double.parseDouble(tmps);
                    } catch (Exception ex) {
                        maxX = -1;
                    }
                }

                // double minY = Double.parseDouble(metainfo.get(
                // MongoVectorDataSet.META_KEY_YMIN).toString());
                tmps = metainfo.get(MongoVectorDataSet.META_KEY_YMIN);
                double minY = 0;
                if (null != tmps) {
                    try {
                        minY = Double.parseDouble(tmps);
                    } catch (Exception ex) {
                        minY = 0;
                    }
                }

                // double maxY = Double.parseDouble(metainfo.get(
                // MongoVectorDataSet.META_KEY_YMAX).toString());
                tmps = metainfo.get(MongoVectorDataSet.META_KEY_YMAX);
                double maxY = -1;
                if (null != tmps) {
                    try {
                        maxY = Double.parseDouble(tmps);
                    } catch (Exception ex) {
                        maxY = -1;
                    }
                }

                try {
                    /*
                     * 数据的矩形范围·~ [ 73.44696 , 6.3186412 , 135.08583 , 53.557926]
                     */
                    //***************因JDK1.6与1.8兼容问题废弃*************************
                    //Array array = rs.getArray("Extent");
                    //Object extents = array.getArray();
                    //Object[] d = (Object[]) extents;
                    //minX = (Double) d[3];
                    //minY = (Double) d[2];
                    //maxX = (Double) d[1];
                    //maxY = (Double) d[0];
                    //************************************************************
                    String extent = rs.getString("Extent");
                    if (extent != null) {
                        extent = extent.replaceAll("[\\[\\]]", "");
                        String[] extents = extent.trim().split(",");
                        minX = Double.parseDouble(extents[0]);
                        minY = Double.parseDouble(extents[1]);
                        maxX = Double.parseDouble(extents[2]);
                        maxY = Double.parseDouble(extents[3]);
                    }

                    // dataInfo.setDataName(dataName);
                    dataInfo.setDataAliasName(dataAliasName);
                    dataInfo.setScaleDenominator(scale);
                    dataInfo.setIsAnnotation(isAnnotation);

                    float[] bounds = new float[4];
                    bounds[0] = (float) minX;
                    bounds[1] = (float) minY;
                    bounds[2] = (float) maxX;
                    bounds[3] = (float) maxY;
                } catch (Exception e) {
                    log.error(e.getMessage(), e.getCause());
                }

                // 2013.08.02.将通过epsg来获取坐标参考对象的代码修改为通过wkt来获取
                // 设置坐标系
                // 2013.08.02.修改将wkt转换为epsg的代码:增加wkt转换epsg的异常捕获,以及赋予默认值
                int epsg = -1;
                GsSpatialReference param = null;
                if (StringUtils.isNotBlank(wktStr)) {
                    param = SpatialRefUtil.getInstance().wktToSpatialRef(wktStr);
                    epsg = SpatialRefUtil.getInstance().WKTToEPSG(wktStr);
                }
                ICoordRefSystem crs = new CoordRefSystem(epsg, wktStr, param);
                dataInfo.setCoordRef(crs);

                /**
                 * 区分三维地名数据
                 */
                // getDataTableName(conn);
                //***************因JDK1.6与1.8兼容问题废弃*************************
                //Array se_array = rs.getArray("ReferenceExtent");
                //Object s_extents = se_array.getArray();
                //Object[] s_d = (Object[]) s_extents;
                //************************************************************
                String refextent = rs.getString("ReferenceExtent");
                double[] s_d = new double[4];
                if (refextent != null) {
                    refextent = refextent.replaceAll("[\\[\\]]", "");
                    String[] extents = refextent.trim().split(",");
                    s_d[3] = Double.parseDouble(extents[0]);
                    s_d[2] = Double.parseDouble(extents[1]);
                    s_d[1] = Double.parseDouble(extents[2]);
                    s_d[0] = Double.parseDouble(extents[3]);
                }

                GeoEnvelope env = null;
                // 新版mongo投影坐标系，矢量数据获取范围
                if("eSimpleFeature".equals(featureType) && !crs.isGeographic()){
                    GsBox gs = inverseAffine(crs, s_d, minX, minY, maxX, maxY);
                    env = new GeoEnvelope(gs);
                } else {
                    env = new GeoEnvelope(minX, maxX, minY, maxY);
                }

                dataInfo.setEnvelope(env);
                dataInfo.setIdColumnName("_id");
                dataInfo.setSpatialColumnName("Geometry");
                dataInfo.setGeometryType(geometryType);

                /* 如果ReferenceExtent有效则可能需要做仿射变换 */
                this._change = (Double) s_d[0] >= (Double) s_d[2];
                if (_change) {
                    // 计算变换参数
                    _referenceExtent[0] = (Double) s_d[3];
                    _referenceExtent[1] = (Double) s_d[2];
                    _referenceExtent[2] = (Double) s_d[1];
                    _referenceExtent[3] = (Double) s_d[0];
                }

                /*
                 * 从 SPATIAL_OBJECT_CLASSES Fields 中取字段信息·~
                 */
                Array arr = rs.getArray("Fields");
                try {
                    ArrayList<String> attrs = new ArrayList<String>();
                    AttributeInfo attrInfo = new AttributeInfo();
                    String columnName = null;

                    MongoArray<BasicDBObject> mongoArr = (MongoArray<BasicDBObject>) arr;
                    Object object = mongoArr.getArray();
                    Object[] objects = (Object[]) object;
                    for (Object o : objects) {
                        BasicDBObject obj = (BasicDBObject) o;
                        columnName = obj.getString("Name");
                        // 2013.08.09.增加OID和Geometry字段的过滤
                        if (columnName.equalsIgnoreCase("_ID")
                                || columnName.equalsIgnoreCase("OID")
                                || columnName.equalsIgnoreCase("GEOMETRY")
                                || columnName.equalsIgnoreCase("_VERSION_")) {
                            continue;
                        }
                        AttributeItem item = new AttributeItem();
                        item.setName(columnName);// 列名称
                        item.setLength(obj.getInt("Precision"));// 列长度
                        String typeAsString = obj.getString("Type");
                        int type = getAttributeType(typeAsString, obj
                                .getInt("Scale"));
                        item.setType(type);// 列类型
                        attrInfo.add(item);
                        attrs.add(columnName);
                    }
                    attributes = new ArrayList();
                    for (int i = 0; i < attrs.size(); i++) { // 遍历属性
                        attributes.add(attrs.get(i));
                    }
                    dataInfo.setAttributeInfo(attrInfo);
                } catch (Exception e) {
                    log.error(e.getMessage(), e.getCause());
                }


            }
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class, e);
        } finally {
            try {
                if (null != rs) {
                    rs.close();
                }
                if (null != stmt) {
                    stmt.close();
                }
                if (null != conn) {
                    conn.close();
                }
            } catch (SQLException e2) {
                log.error(e2.getMessage(), e2.getCause());
            }
        }

        log.debug("MongoVectorDataSet 初始化完成.");
        log.debug(this.toString());

        // 20131008.3 根据数据源对象中是否预加载的标志进行预加载
        Map<String, String> properties = this.dsInfo.getProperties();
        if (null == properties) {
            return;
        }

        String preloadStr = properties.get("PreLoadable");
        if (null == preloadStr) {
            return;
        }

        boolean preload = Boolean.parseBoolean(preloadStr);
        if (!preload) {
            return;
        }
        String[] attrNames = null;
        if (null == attributes) {
            attrNames = new String[0];
        } else {
            int size = attributes.size();
            attrNames = new String[size];

            for (int i = 0; i < size; i++) {
                attrNames[i] = attributes.get(i);
            }
        }
        cacheDataSet = new FeatureDataLoader(dsInfo, dataInfo, attrNames, this);
        cacheDataSet.init();
    }

    /**
     * 投影坐标系 映射范围转真实范围
     * @param crs 坐标参考
     * @param s_d 数据库中存储的参考系范围
     * @param minX 数据库中读取到的最小x
     * @param minY 数据库中读取到的最小y
     * @param maxX 数据库中读取到的最大x
     * @param maxY 数据库中读取到的最大y
     * @return 经过变换后的真实范围
     */
    private GsBox inverseAffine(ICoordRefSystem crs, double[] s_d, double minX, double minY, double maxX, double maxY) {
        double[] box = crs.queryProjectedBounds();
        GsBox tmp = new GsBox(box[0], box[1], box[2], box[3]);
        // 如果是不是有效的box, 使用数据库存储的box
        if (!tmp.IsValid()) {
            // 如果疑惑为什么是反向的 看一下s_d怎么得来的
            tmp.Set(s_d[3], s_d[2], s_d[1], s_d[0]);
            // 如果数据库中不是有效的, 使用固定值
            if (!tmp.IsValid()) {
                double extx = 20037508.3427892430765884088807;
                double exty = 20037508.3427892430765884088807;
                tmp.Set(-extx, -exty, extx, exty);
            }
        }
        double width = tmp.Width();
        double height = tmp.Height();
        GsBox gsBox = new GsBox();
        // 内核算法，将0-1范围映射为真实范围
        gsBox.setXMin(width * minX + tmp.getXMin());
        gsBox.setYMin(height * minY + tmp.getYMin());
        gsBox.setXMax(width * maxX + tmp.getXMin());
        gsBox.setYMax(height * maxY + tmp.getYMin());

        return gsBox;
    }

    /**
     * 投影坐标系 真实范围转索引范围
     * @param x 横坐标
     * @param y 纵坐标
     * @return 返回范围坐标
     */
    private double[] directAffine(double x, double y){
        ICoordRefSystem coordRef = dataInfo.getCoordRef();
        double[] box = coordRef.queryProjectedBounds();
        GsBox tmp = new GsBox(box[0], box[1], box[2], box[3]);
        // 如果是不是有效的box, 使用数据库存储的box
        if (!tmp.IsValid()) {
            tmp.Set(_referenceExtent[0], _referenceExtent[1], _referenceExtent[2], _referenceExtent[3]);
            // 如果数据库中不是有效的, 使用固定值
            if (!tmp.IsValid()) {
                double extx = 20037508.3427892430765884088807;
                double exty = 20037508.3427892430765884088807;
                tmp.Set(-extx, -exty, extx, exty);
            }
        }
        double width = tmp.Width();
        double height = tmp.Height();
        double indexX = (x - tmp.getXMin()) / width;
        double indexY = (y - tmp.getYMin()) / height;

        return new double[]{indexX, indexY};
    }

    /**
     * 获取数据库中字段对应的类型
     *
     * @param sqltypeAsString 数据库中读取出来的类型标示
     * @param scale           小数点后的位数，如果不是double和float类型，则该值为0
     * @return java.sql.Types中对应的数据类型
     */
    public static int getAttributeType(String sqltypeAsString, int scale) {
        String t = sqltypeAsString.toUpperCase();
        int sqltype = 0;
        // 适配短整型
        if ("INTEGER".equals(t) || "TINYINT".equals(t) || "DECIMAL".equals(t)) {
            sqltype = Types.INTEGER;
        } else if ("DOUBLE".equals(t) || "REAL".equals(t)) {
            sqltype = Types.DOUBLE;
        } else if ("BOOLEAN".equals(t)) {
            sqltype = Types.BOOLEAN;
        } else if ("FLOAT".equals(t)) {
            sqltype = Types.FLOAT;
        } else if ("VARCHAR".equals(t) || "CHAR".equals(t) || "NULL".equals(t)) {
            sqltype = Types.VARCHAR;
        } else if ("BLOB".equals(t)) {
            sqltype = Constants.TYPE_BLOB;
        } else if ("CLOB".equals(t)) {
            sqltype = Constants.TYPE_CLOB;
        } else if ("DATE".equals(t)) {
            sqltype = Constants.TYPE_DATE;
        } else if ("ESHORTTYPE".equals(t) || "EUSHORTTYPE".equals(t)) { // 适配短整型
            sqltype = Types.SMALLINT;
        }
        // 基本上可以直接返回，暂保留以下原始代码·~

        // 20130606.修改原来判断属性字段类型的代码,因为原来将数字类型的属性字段都当成字符类型,所以导致属性符号中,两个应该比较数字大小的位置变成比较字符串了
        int type;
        switch (sqltype) {
            case Types.NUMERIC: // 2
                // 20140905. 取出的数据精度小于0，把判断由原来的 ==0 改成了 <=0
                if (scale <= 0) {
                    type = Types.INTEGER;
                } else {
                    type = Types.DOUBLE;
                }
                break;
            case Types.BOOLEAN:
                type = Types.BOOLEAN;
                break;
            case Types.DOUBLE:
                type = Types.DOUBLE;
                break;
            case Types.INTEGER:
            case Types.TINYINT:
            case Types.DECIMAL:
                type = Types.INTEGER;
                break;
            case Types.FLOAT:
                type = Types.FLOAT;
                break;
            case Types.NULL:
            case Types.CHAR:
            case Types.VARCHAR:
                type = Types.VARCHAR;
                break;
            case Types.BLOB: // -6
                type = Constants.TYPE_BLOB;
                break;
            case Types.CLOB: // -6
                type = Constants.TYPE_CLOB;
                break;
            case Types.DATE:
                type = Constants.TYPE_DATE;
                break;
            case Types.SMALLINT:
                type = Constants.TYPE_SHORT;
                break;
            default:
                type = sqltype;
                break;
        }
        return type;
    }

    @Override
    public DataSourceInfo getDataSourceInfo() {
        this.dsInfo.getConnectionInfo().setPoolName(poolName);
        return this.dsInfo;
    }

    @Override
    public IDataSetInfo getDataInfo() {
        return dataInfo;
    }

    @Override
    public String getMetaInfo() {
        return null;
    }

    @Override
    public void setMetaInfo(String metaInfo) {

    }

    @Override
    public boolean isDataRoom() {
        return false;
    }

    @Override
    public boolean createIndex(IndexInfo indexInfo) throws DataSetException {
        return false;
    }

    @Override
    public boolean removeIndex(String indexName) throws DataSetException {
        return false;
    }

    @Override
    public boolean rebuildIndex(String indexName) throws DataSetException {
        return false;
    }

    @Override
    public IndexInfo[] getIndexInfos() {
        return null;
    }

    @Override
    public IFeatureCursor query(IFeatureFilter filter) throws DataSetException {
        if (null == filter) {
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.FILTER_TERM_NULL);
        }
        // 20131008.2 在已完成预加载的缓存数据集中进行查询
        if (null != this.cacheDataSet && this.cacheDataSet.hasLoaded()) {
            return this.cacheDataSet.query(filter);
        }
        // sql语句
        String sql = resolveFilter(filter, false);
        log.debug("SQL: " + sql);
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        MongoFeatureCursor cursor = null;
        try {
            /* 构建IGeometryParser实例 */
            MongoExecutor.setGeometryParser(new GeometryParser());
            conn = dbcManager.getConnection(poolName);
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            cursor = new MongoFeatureCursor(conn, stmt, rs, dataInfo, filter,
                    endian, this.spatialOperation);
        } catch (SQLException e) {
            freeConn(rs, stmt, null, conn);
            log.error(e.getMessage(), e.getCause());
            Object[] args = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_SEARCH_FAILURE, args, e);
        }
        return cursor;
    }

    @Override
    public int queryHits(IFeatureFilter filter) throws DataSetException {
        if (null == filter) {
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.FILTER_TERM_NULL);
        }
        // 20131008.2 在已完成预加载的缓存数据集中进行查询
        if (null != this.cacheDataSet && this.cacheDataSet.hasLoaded()) {
            return this.cacheDataSet.queryHits(filter);
        }
        // sql语句
        String sql = resolveFilter(filter, true);
        log.debug("SQL: " + sql);
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        int count = 0;
        try {
            /* 构建IGeometryParser实例 */
            MongoExecutor.setGeometryParser(new GeometryParser());
            conn = dbcManager.getConnection(poolName);
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            if (rs.next()) {
                count = rs.getInt(1);
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e.getCause());
            Object[] args = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_SEARCH_FAILURE, args, e);
        } finally {
            try {
                if (null != rs) {
                    rs.close();
                }

                if (null != stmt) {
                    stmt.close();
                }

                if (null != conn) {
                    conn.close();
                }
            } catch (SQLException e2) {
                log.error(e2.getMessage(), e2.getCause());
            }
        }
        return count;
    }

    /**
     * 解析FeatureFilter对象
     *
     * @param filter IFeatureFilter 过滤条件
     * @return 查询sql语句
     */
    protected String resolveFilter(IFeatureFilter filter, boolean queryHits) {
        // where条件是否有效
        boolean isPrepared = true;// filter.isPreparedStatementSupported();
        // 2013.06.17.增加where条件为空的判断
        String whereStr = null;
        if (isPrepared) {
            whereStr = filter.getPreparedWhereCause();
        }
        if (null == whereStr || "".equals(whereStr)) {
            whereStr = "1=1";
        }
        // 查询的字段名称
        String[] attrArray = filter.resultAttributeNames();
        // 20130802.2 区分处理返回字段数组为null和长度为0的情况，为null时查询全部属性，长度为0时不查属性
        if (null == attrArray) {
            attrArray = new String[attributes.size()];
            attrArray = attributes.toArray(attrArray);
        }

        // 返回结果类型
        String resultType = filter.getResultType();

        StringBuffer sql = new StringBuffer();
        if (filter instanceof FeatureFilter) {
            createFilterSql(sql, null, null, null, null, true, attrArray,
                    queryHits, resultType, 0, filter);
            if (null != whereStr && !"".equals(whereStr) && isPrepared) {
                sql.append(" where ");
                sql.append(whereStr);
            }
        } else if (filter instanceof ISpatialFilter) {
            SpatialFeatureFilter sFilter = (SpatialFeatureFilter) filter;
            // 空间几何对象
            List<GeoGeometry> geometries = sFilter.getGeometries(this.dataInfo
                    .getCoordRef());
            if (null != geometries && !geometries.isEmpty()) {
                // 保存空间几何数据的字段名称，默认为GEOMETRY
                // String geometryFiled = "GEOMETRY";
                List<GeoGeometry> geoms = new ArrayList<GeoGeometry>();
                // 空间查询筛选条件
                List<SpatialRelationType> relationTypes = sFilter
                        .getSpatialRelations();
                List<SpatialRelationType> spatialOperations = new ArrayList<SpatialRelationType>();
                if (null != relationTypes && !relationTypes.isEmpty()) {
                    this.spatialOperation = relationTypes.get(0);
                    spatialOperations.addAll(relationTypes);
                }
                // 容差
                float tolerance = sFilter.getTolerance();
                double distance = sFilter.getDistance();
                // DWITHIN查询中使用的缓冲区范围
                List<Double> distances = new ArrayList<Double>();
                distances.add(distance);

                // 投影类型
                ICoordRefSystem coordRefSystem = sFilter.getCoordRef();
//				int projectionID = (null == coordRefSystem || null == coordRefSystem
//						.getCoordRefParam()) ? 1 : coordRefSystem
//						.getCoordRefParam().getProjectionID();
                boolean projection = true;
                if (coordRefSystem != null && coordRefSystem.getCoordRef() != null) {
                    projection = coordRefSystem.getCoordRef().IsGeographic();
                }

                List<String> spatialWhere = createFilterSql(sql, geometries,
                        geoms, spatialOperations, distances, projection,
                        attrArray, queryHits, resultType, tolerance, sFilter);

                if (!geoms.isEmpty()) {
                    sFilter.setGeometries(geoms);
                }

                if (null != whereStr && !"".equals(whereStr)) {
                    for (String str : spatialWhere) {
                        whereStr = replace(whereStr, str);
                    }
                }
                if (!isPrepared) {
                    whereStr = null;
                }
                /* 把占位符给去掉·~ */
                if (null != whereStr && whereStr.contains("(&&&)")) {
                    whereStr = whereStr.replace("(&&&)", "");
                }

                if (null != whereStr && !"".equals(whereStr)) {
                    sql.append(" where ").append(whereStr);
                }
            } else {
                if (null != whereStr && whereStr.contains("(&&&)")) {
                    whereStr = whereStr.replace("(&&&)", "");
                }
                createFilterSql(sql, null, null, null, null, true, attrArray,
                        queryHits, resultType, 0, filter);
                if (null != whereStr && !"".equals(whereStr) && isPrepared) {
                    sql.append(" where ");
                    sql.append(whereStr);
                }
            }
        }
        // 分组字段
        String groupFields = filter.groupFields();
        if (null != groupFields && !"".equals(groupFields)) {
            sql.append(" group by ");
            sql.append(groupFields);
        }
        // 排序条件
        String orderCause = filter.orderCause();
        if (null != orderCause && !"".equals(orderCause)) {
            sql.append(" order by ");
            sql.append(orderCause);
        }
        String sqlAsString = sql.toString();
        if (sqlAsString.endsWith(" where 1=1")) {
            sqlAsString = sqlAsString.substring(0, sqlAsString
                    .indexOf(" where 1=1"));
        } else if (sqlAsString.indexOf("where 1=1 AND") > -1) {
            sqlAsString = sqlAsString.replace("where 1=1 AND", "where");
        } else if (sqlAsString.indexOf("where 1=1") > -1) {
            sqlAsString = sqlAsString.replace("where 1=1", " ");
        }
        //处理数据库分页查询要素问题
        int startNum = 0;
        int maxFeatures = filter.getMaxFeatures();
        if (null != filter.getStartNo() && filter.getStartNo() > 0) {
            // 分页查询
            startNum = filter.getStartNo() - 1;
            if (null != filter.getEndNo() && filter.getEndNo() > startNum) {
                sqlAsString += " LIMIT " + (filter.getEndNo() - startNum) + " OFFSET "+ startNum;
            } else {
                sqlAsString += " LIMIT " + maxFeatures + " OFFSET " + startNum;
            }
        } else {
            // 返回要素最大条数
            sqlAsString += " limit " + maxFeatures;
        }
        return sqlAsString;
    }

    /**
     * 生成查询语句，不包含where子句及排序子句
     *
     * @param buffer
     *            字符串缓冲对象
     *
     * @param attrArray
     *            查询字段集合
     */
    // private void spiliceSearcheFiled(StringBuffer buffer, String[] attrArray,
    // boolean queryHits, boolean queryGeometry) {
    //
    // buffer.append("SELECT ");
    // if (queryHits) {
    // buffer.append("count(*)");
    // } else {
    // 增加注记类型的判断;如果是注记,则sql语句的查询字段改为查所有字段
    // GeometryType type = dataInfo.getGeometryType();
    // if (type == GeometryType.ANNOTATION) {
    // buffer.append("*");
    // } else {
    // String oidFiled = dataInfo.getIdColumnName();
    // String geometryFiled = dataInfo.getSpatialColumnName();
    //
    // int size = 0;
    // buffer.append("");
    // buffer.append(oidFiled);
    // buffer.append(" ,");
    // buffer.append("");
    // buffer.append(geometryFiled);
    // buffer.append("");
    //
    // if (null != attrArray) {
    // size = attrArray.length;
    // }
    // for (int i = 0; i < size; i++) {
    // String attr = attrArray[i];
    // if (attr.equalsIgnoreCase(oidFiled)
    // || attr.equalsIgnoreCase(geometryFiled)) {
    // continue;
    // }
    //
    // if (i < size) {
    // buffer.append(",");
    // }
    // buffer.append("");
    // buffer.append(attr);
    // }
    // }
    // }
    // buffer.append(" FROM ");
    // buffer.append(dataTableName);
    // buffer.append("");
    // if (queryGeometry) {
    // // buffer.append(" ,system.indexes i ");
    // }
    // }

    /**
     * 拼接where子句及排序子句
     *
     * @param buffer
     *            缓冲字符串
     * @param whereStr
     *            where子句
     * @param orderStr
     *            排序子句
     */
    // private void spiliceWhereSQL(StringBuffer buffer, String whereStr,
    // String orderStr) {
    // if (null != whereStr && !"".equals(whereStr)) {
    // buffer.append(" WHERE ");
    // buffer.append(whereStr);
    // }
    //
    // if (null != orderStr && !"".equals(orderStr)) {
    // orderStr = addFiledPrefix(orderStr);
    // buffer.append(" order by ");
    // buffer.append(orderStr);
    // }
    // }

    /**
     * 解析空间过滤条件，生成where子句
     *
     * @param geometries
     *            空间几何对象
     *
     * @param geometryFiled
     *            保存空间数据的字段名称
     *
     * @param relationTypes
     *            空间关系
     *
     * @param tolerance
     *            容差
     *
     * @return sql语句
     */
    // private String spliceSpatialSearcheSQL(List<GeoGeometry> geometries,
    // String geometryFiled, List<SpatialRelationType> relationTypes,
    // float tolerance, String whereStr) {
    // if (null == geometries) {
    // // return " d.oid = i.oid ";
    // return whereStr;
    // }
    // StringBuilder sb = new StringBuilder();
    // final int size = geometries.size();
    // for (int i = 0; i < size; i++) {
    // GeoGeometry geometry = geometries.get(i);
    // if (null == geometry) { // 空间对象为空则跳过
    // continue;
    // }
    // String geomtetryType = geometry.getGeometryType();
    //
    // GeoEnvelope env = geometry.getEnvelopeInternal();
    // double minx = env.getMinX();
    // double miny = env.getMinY();
    // double maxx = env.getMaxX();
    // double maxy = env.getMaxY();
    //
    // if ("Point".equals(geomtetryType)) {
    // double x = env.getMinX();
    // double y = env.getMinY();
    // minx = x - tolerance;
    // maxx = x + tolerance;
    // miny = y - tolerance;
    // maxy = y + tolerance;
    // }
    // String where = "(" + maxx + " >= i.xmin and " + minx
    // + "  <= i.xmax and " + maxy + " >= i.ymin and " + miny
    // + " <= i.ymax" + ")";
    // if (null == whereStr) {
    // whereStr = where;
    // }
    // // else {
    // // whereStr = whereStr.replaceFirst("&&&", where);
    // // }
    // // 2013.07.19.增加"&&&"占位符的判断
    // else if (whereStr.indexOf("&&&") >= 0) {
    // whereStr = whereStr.replaceFirst("&&&", where);
    // } else {
    // // 2013.06.26.如果不存在占位符,则直接将空间条件拼接上去
    // whereStr = whereStr + " AND " + where;
    // }
    // }
    // sb.append(whereStr);
    // sb.append(" and d.oid = i.oid ");
    // return sb.toString();
    // }

    /**
     * 向属性字段名称前追加前缀，防止联合查询中不指定表名导致的sqlexception
     *
     * @param whereStr
     *            where条件
     *
     * @return 调整后的where条件
     */
    // private String addFiledPrefix(String whereStr) {
    // if (null == whereStr || "".equals(whereStr)) {
    // return whereStr;
    // }
    // whereStr = " " + whereStr;
    // int size = attributes.size();
    // for (int i = 0; i < size; i++) {
    // String filed = attributes.get(i);
    // if (whereStr.contains(" " + filed + " ")) {
    // whereStr = whereStr.replace(" " + filed + " ", " " + "" + filed
    // + " ");
    // }
    // }
    // return whereStr;
    // }

    /**
     * 生成带?占位符的filter查询语句
     *
     * @param sql
     * @param geometries
     * @param geoms
     * @param spatialOperations
     * @param distances
     * @param projectionID
     * @param queryHits
     * @param resultType
     * @return
     */
    protected List<String> createFilterSql(StringBuffer sql,
                                           List<GeoGeometry> geometries, List<GeoGeometry> geoms,
                                           List<SpatialRelationType> spatialOperations,
                                           List<Double> distances, boolean projectionID, String[] attrArray,
                                           boolean queryHits, String resultType, float tolerance, IFeatureFilter filter) {
        // 20130802.2 区分处理返回字段数组为null和长度为0的情况，为null时查询全部属性，长度为0时不查属性
        if (attrArray == null) {
            return new ArrayList<String>();
        }

        List<String> geometrySqlList = new ArrayList<String>();

        parseSpatialSqlToList(geometries, geoms, spatialOperations, distances,
                projectionID, geometrySqlList, tolerance);

        // 替换&&&字符串为正常的空间查询语句
        // for (int j = 0; j < geometrySqlList.size(); j++) {
        // whereSql = whereSql.replaceFirst("&&&", geometrySqlList.get(j));
        // }

        sql.append("SELECT ");
        if (queryHits) {
            sql.append("count(*)");
        } else {
            this.insertOIDAndAttributes(sql, attrArray, resultType, filter);
        }

        sql.append(" FROM ");
        sql.append(tableName);
        sql.append(" A");

        return geometrySqlList;
    }

    /**
     * 解析出空间sql查询语句 wanen2015.6.26 方便子类使用
     */
    protected void parseSpatialSqlToList(List<GeoGeometry> geometries,
                                         List<GeoGeometry> geoms,
                                         List<SpatialRelationType> spatialOperations,
                                         List<Double> distances, boolean projectionID,
                                         List<String> geometrySqlList, float tolerance) throws DataSetException {
        if (null != spatialOperations && !spatialOperations.isEmpty()) {
            for (int i = 0; i < spatialOperations.size(); i++) {
                SpatialRelationType spatialOperation = spatialOperations.get(i);

                GeoGeometry g = geometries.get(i);
                String gtype = g.getGeometryType();
                //Mongo 2.6以下版本不支持多点、多线、多面的查询，这里是临时解决方案
                //**********使用了2.6及以上的版本，以下代码需要调整**************
//				if(gtype.equalsIgnoreCase("MultiPoint") || gtype.equalsIgnoreCase("MultiLineString") 
//						|| gtype.equalsIgnoreCase("MultiPolygon") || gtype.equalsIgnoreCase("LineString"))
//				{
                g = g.getEnvelope();
//				}
                //***************************************************
                GeoGeometryFactory gf = new GeoGeometryFactory();
                if ("Point".equals(gtype) || "MultiPoint".equals(gtype)) {
                    GeoEnvelope env = g.getEnvelopeInternal();
                    env.expandBy(tolerance * 100);
                    g = gf.toGeometry(env);
                }

                //与数据范围求交
                GeoEnvelope dataEnv = dataInfo.getEnvelope();
                GeoEnvelope copyDataEnv = new GeoEnvelope(dataEnv);
                // TODO 20210315 不扩大容差，修复Bug 3541
//                copyDataEnv.expandBy(tolerance * 20000000);
                copyDataEnv.expandBy(tolerance);
                GeoGeometry bound = gf.toGeometry(copyDataEnv);
                g = g.intersection(bound);
                if (null == g) {
                    log.error("请求查询范围中第" + i + "组参数值超出最大范围限制！");
                    throw new DataSetException(MongoVectorDataSet.class, TextCodesConst.DATASET_QUERY_ERROR, new Throwable("请求查询范围参数值超出最大范围限制！"));
                }
                /* 做一次仿射变换·~ */
                if (_change) {
                    double[][] xy = g.getCoordinates();
                    double[][] _xy = new double[xy.length][2];
                    for (int j = 0; j < xy.length; j++) {
                        // 如果是新数据，使用新的仿射方法
                        if ("eSimpleFeature".equals(featureType)) {
                            double[] tmp_xy = this.directAffine(xy[j][0], xy[j][1]);
                            _xy[j] = tmp_xy;
                        } else {
                            double tmp_x = this.coordinateToAffine(xy[j][0], true, false);
                            double tmp_y = this.coordinateToAffine(xy[j][1], false, true);
                            _xy[j] = new double[]{tmp_x, tmp_y};
                        }
                    }
                    GeoGeometryFactory fac = new GeoGeometryFactory();
                    g = fac.createMultiPoint(_xy).getEnvelope();

                    // TODO 由于内核精度支持不足，屏蔽掉全图范围和小范围数据的求交
//                    GeoEnvelope maxEnvelope = new GeoEnvelope(-180, 180, -90, 90);
//                    //由于mongo数据库空间查询仅支持正常的-180,180，-90,90的访问查询，因此在一些时候，做动态投影会出现查询访问溢出的情况，所以这里用查询的范围和数据原始范围进行求交，然后用求交后的范围完成查询
//                    g = g.intersection(gf.toGeometry(maxEnvelope));
                }
                if (null == g) {
                    log.error("请求查询范围中第" + i + "组参数值超出最大范围限制！");
                    throw new DataSetException(MongoVectorDataSet.class, TextCodesConst.DATASET_QUERY_ERROR, new Throwable("请求查询范围参数值超出最大范围限制！"));
                } else {
                    String gText = g.toText();
                    String geometrySql = "";
                    switch (spatialOperation) {
                        case SPATIAL_RELATION_INTERSECTS:
                        case SPATIAL_RELATION_ENVELOPE_INTERSECTS:
                        case SPATIAL_RELATION_TOUCHES:
                        case SPATIAL_RELATION_OVERLAPS:
                        case SPATIAL_RELATION_CROSSES:
                        case SPATIAL_RELATION_CONTAINS:
                        case SPATIAL_RELATION_BBOX:
                        case SPATIAL_RELATION_EQUALS:
                        case SPATIAL_RELATION_WITHIN:
                            geometrySql = "MBR $$$intersects " + gText + "$$$";
                            break;
//					case SPATIAL_RELATION_WITHIN:
//						//支持 box、cneter、polygon
//						if(gtype.equalsIgnoreCase("Polygon") || gtype.equalsIgnoreCase("Box") || gtype.equalsIgnoreCase("Center")){
//							geometrySql = "MBR $$$within " + gText + "$$$";
//						}else{
//							//其他的mongo不支持，只能采用相交粗插，再做过滤
//							geometrySql = "MBR $$$intersects " + gText + "$$$";
//						}
//						break;
                        case SPATIAL_RELATION_DWITHIN:
                            if (null == distances || distances.isEmpty()) {
                                break;
                            } else {
                                double distance = distances.get(i);
                                if (0 < distance) {
                                    if (projectionID) {
                                        // 1米相当于多少度
                                        double degree = 8.9906789136362875788526245415066e-6;
                                        g = g.buffer(distance * degree);
                                    } else {
                                        g = g.buffer(distance);
                                    }
                                    geoms.add(g);
                                    gText = g.toText();
                                }
                            }
                            geometrySql = "MBR $$$intersects " + gText + "$$$";
                            break;
                        default:
                            geometrySql = " 1 == 1 ";
                            break;
                    }
                    geometrySqlList.add(geometrySql);
                }
            }
        }
    }

    /**
     * 坐标转换
     *
     * @param val
     * @param x
     * @param y
     * @return
     */
    private double coordinateToAffine(double val, boolean x, boolean y) {
        double tmp = 0;
        double minX = _referenceExtent[0];
        double minY = _referenceExtent[1];
        double maxX = _referenceExtent[2];
        double maxY = _referenceExtent[3];
        if (x) {
            tmp = ((val - minX) / (maxX - minX)) * 360 - 180;
        }
        if (y) {
            tmp = ((val - minY) / (maxY - minY)) * 180 - 90;
        }
        return tmp;
    }

    protected void insertOIDAndAttributes(StringBuffer sql, String[] attrArray,
                                          String resultType, IFeatureFilter filter) {
        StringBuffer buf = new StringBuffer();
        String oidFiled = dataInfo.getIdColumnName();
        String geometryFiled = dataInfo.getSpatialColumnName();
        if (filter.isQueryID()) {
            if (!"statistics".equalsIgnoreCase(resultType)) {
                buf.append("A." + oidFiled + " AS OID").append(", ");
                buf.append("A." + geometryFiled + " AS GEOMETRY").append(", ");
            }
        }

        if (attrArray != null && attrArray.length > 0) {
            for (int i = 0, num = attrArray.length; i < num; i++) {
                String attr = attrArray[i].trim();
                // 4.5.1.20110727.1 拼接sql语句时排除空间数据列 ，该列会在后面的处理流程中拼接，避免重复字段
                if (!"".equals(attr) && !attr.equalsIgnoreCase(oidFiled)
                        && !attr.equalsIgnoreCase(geometryFiled)) {
                    buf.append(attr.toUpperCase()).append(", ");
                }
            }
        }

        String sb = buf.toString();
        if (null != sb && sb.endsWith(", ")) {
            sb = sb.substring(0, sb.lastIndexOf(", "));
        }
        sql.append(sb);
    }

    /**
     * wanen2015.5.26子类需要复用 改变访问控制为protected 另外raplace拼错,改成replace
     */
    protected String replace(String sql, String str) {
        if (sql.indexOf("&&&") >= 0) {
            // 20140517.1 修改空间查询条件的字符串替换方式
            // sql = sql.replaceFirst("&&&", str);
            int idx = sql.indexOf("&&&");
            String sql1 = sql.substring(0, idx);
            String sql2 = sql.substring(idx + 3);
            sql = sql1 + str + sql2;
        } else {
            // 2013.06.26.如果不存在占位符,则直接将空间条件拼接上去
            sql = sql + " AND " + str;
        }
        return sql;
    }

    @Override
    public IFeatureCursor getAllFeatures() throws DataSetException {
        FeatureFilter filter = new FeatureFilter();
        filter.setPreparedWhereCause("");
        IFeatureCursor cursor = query(filter);
        return cursor;
    }

    @Override
    public IFeature getFeature(long oid) throws DataSetException {
        // sql语句
        StringBuffer sbSql = getQueryString();
        sbSql.append("where _id = ?");
        String sql = sbSql.toString();
        log.debug("getFeature_SQL : " + sql);
        Connection conn = null;
        ResultSet rs = null;
        PreparedStatement ps = null;
        MongoFeatureCursor cursor = null;
        try {
            conn = dbcManager.getConnection(poolName);
            ps = conn.prepareStatement(sql);
            ps.setLong(1, oid);
            rs = ps.executeQuery();
            cursor = new MongoFeatureCursor(conn, ps, rs, dataInfo, null,
                    endian, this.spatialOperation);
            if (null != cursor) {
                if (cursor.hasNext()) {
                    IFeature feature = cursor.getNext();
                    return feature;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e.getCause());
            Object[] args = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_SEARCH_FAILURE, args, e);
        } finally {
            if (null == cursor) {
                ObjectCloser.close(rs);
                ObjectCloser.close(ps);
                ObjectCloser.close(conn);
            } else {
                cursor.close();
            }
        }
        return null;
    }

    @Override
    public IFeatureCursor getFeatures(long... oids) throws DataSetException {
        FeatureFilter filter = new FeatureFilter();
        StringBuffer sbSql = new StringBuffer();
        sbSql.append("_id IN (");
        int len = oids.length;
        for (int i = 0; i < len; i++) {
            if (i != len - 1) {
                sbSql.append(oids[i]).append(",");
            } else {
                sbSql.append(oids[i]);
            }
        }
        sbSql.append(")");
        filter.setPreparedWhereCause(sbSql.toString());
        IFeatureCursor cursor = query(filter);
        return cursor;
    }

    @Override
    public int getTotalNumber() throws DataSetException {
        String sql = "SELECT COUNT(*) FROM " + tableName;
        log.debug("查询数据个数---" + sql);
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        int count = 0;
        try {
            conn = dbcManager.getConnection(poolName);
            ps = conn.prepareStatement(sql);
            rs = ps.executeQuery();
            if (rs.next()) {
                count = rs.getInt(1);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            Object[] args = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_SEARCH_FAILURE, args, e);
        } finally {
            // 关闭连接
            freeConn(rs, null, ps, conn);
        }
        return count;
    }

    /**
     * 获取查询语句
     *
     * @return
     */
    private StringBuffer getQueryString() {
        StringBuffer sbSql = new StringBuffer("select ");

        String oidFiled = dataInfo.getIdColumnName();
        String geometryFiled = dataInfo.getSpatialColumnName();

        int size = 0;
        sbSql.append("A." + oidFiled + " AS OID");
        sbSql.append(",");
        sbSql.append("A." + geometryFiled + " AS GEOMETRY");

        if (null != attributes) {
            size = attributes.size();
        }
        for (int i = 0; i < size; i++) {
            String attr = attributes.get(i);
            if (attr.equalsIgnoreCase(oidFiled)
                    || attr.equalsIgnoreCase(geometryFiled)) {
                continue;
            }

            if (i < size) {
                sbSql.append(",");
            }
            sbSql.append(attr);
        }

        sbSql.append(" from ");
        sbSql.append(this.tableName + " A ");
        return sbSql;
    }

    /**
     * 插入一条要素
     *
     * @param feature 要素对象
     * @return 插入成功的要素对象
     */
    @Override
    public IFeature insertFeature(IFeature feature) throws DataSetException {
        if (null == feature || !checkFeatureAttribute((BaseFeature) feature)) { // 若矢量要素为空则返回空或若矢量要素不复合结构要求则返回空
            return null;
        }

        Connection conn = null;
        try {
            GeoGeometry geometry = feature.getGeometry();
            if (null == geometry) { // 若插入的空间几何对象为空则返回空
                return null;
            }
            /*
             * 1、判断范围是否在数据范围内·~ 2、换算MBR·~ 3、构建SQL`~ 4、执行插入·~
             */
            GeoEnvelope env = this.dataInfo.getEnvelope();
            GeoEnvelope envTemp = geometry.getEnvelopeInternal();
            if (envTemp.getMinX() < env.getMinX()
                    || envTemp.getMaxX() > env.getMaxX()
                    || envTemp.getMinY() < env.getMinY()
                    || envTemp.getMaxY() > env.getMaxY()) {
                // 说明不在矩形范围内·~ 不允许插入·~
            } else {

            }

            AttributeInfo attrInfo = feature.getAttributeInfo();
            AttributeValue[] attrValues = feature.getAttributes();
            // 实际拼接sql用到的属性名称
            // List<String> reqAttrName = new ArrayList<String>();
            // 实际插入到数据库中的字段值
            // List<AttributeValue> reqAttrValue = new
            // ArrayList<AttributeValue>();
            // 字段的数据类型
            // List<Integer> attrType = new ArrayList<Integer>();
            conn = dbcManager.getConnection(poolName);
            MongoConnection mc = this.getConnection(conn);
            DBCollection coll = mc.getDB().getCollection(this.tableName);
            List<AttributeItem> l = attrInfo.getAttributeItems();
            BasicDBObject query = new BasicDBObject();
            // 获取待插入id
            Integer nextOID = getNextOID();
            // 构建一个新的OID·~
            long oid = GUID64Utils.randomGUID64();
            if (nextOID != null){
                oid = (long) nextOID;
            }
            query.put("_id", oid);

            for (int i = 0, num = attrInfo.getAttributeNumber(); i < num; i++) {
                AttributeValue attrValue = attrValues[i];
                AttributeItem item = l.get(i);
                String key = item.getName();
                query.put(key, attrValue);
                if (null != attrValue) {
                    AttributeValue value = attrValue;
                    switch (item.getType()) {
                        case Constants.TYPE_BOOLEAN:
                            String s = value.getBoolean() ? "T" : "F";
                            query.put(key, s);
                            break;
                        case Constants.TYPE_BYTE:
                            query.put(key, value.getByte());
                            break;
                        case Constants.TYPE_CHAR:
                        case Constants.TYPE_STRING:
                            query.put(key, value.getString());
                            break;
                        case Constants.TYPE_DATE:
                        case Constants.TYPE_TIMESTAMP:
                        case Constants.TYPE_TIME:
                            query.put(key, new Timestamp(value.getLong()));
                            break;
                        case Constants.TYPE_DOUBLE:
                            query.put(key, value.getDouble());
                            break;
                        case Constants.TYPE_FLOAT:
                            query.put(key, value.getFloat());
                            break;
                        case Constants.TYPE_SHORT:
                            query.put(key, value.getShort());
                            break;
                        case Constants.TYPE_INTEGER:
                            query.put(key, value.getInt());
                            break;
                        case Constants.TYPE_LONG:
                            query.put(key, value.getLong());
                            break;
                        case Constants.TYPE_BLOB:
                            query.put(key, (Blob) null);
                            break;
                        default:
                            break;
                    }
                }
            }

            byte[] bytes = writer.write(geometry);
            GeoGeometry g = geometry.getEnvelope();
            /* 做一次仿射变换·~ */
            if (_change) {
                double[][] xy = g.getCoordinates();
                double[][] _xy = new double[xy.length][2];
                for (int i = 0; i < xy.length; i++) {
                    // 如果是新数据，使用新的仿射方法
                    if ("eSimpleFeature".equals(featureType)) {
                        double[] tmp_xy = this.directAffine(xy[i][0], xy[i][1]);
                        _xy[i] = tmp_xy;
                    } else {
                        double tmp_x = this.coordinateToAffine(xy[i][0], true, false);
                        double tmp_y = this.coordinateToAffine(xy[i][1], false, true);
                        _xy[i] = new double[]{tmp_x, tmp_y};
                    }
                }
                GeoGeometryFactory fac = new GeoGeometryFactory();
                g = fac.createMultiPoint(_xy).getEnvelope();
            }

            BasicDBObject obj_MBR = new GeometryParser().buildMBR(g);

            Binary b = new Binary(bytes);
            query.put("Geometry", b);
            query.put("MBR", obj_MBR);

            feature.setOID(oid);
            coll.insert(query);
            return feature;
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_INSTER_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
    }

    /**
     * 插入一组要素
     *
     * @param features 要素集合
     * @return 插入成功的要素集合
     */
    @Override
    public List<IFeature> insertFeatures(List<IFeature> features)
            throws DataSetException {
        if (null == features) { // 矢量要素集合为空则返回空
            return null;
        }

        Connection conn = null;
        List<IFeature> list = new ArrayList<IFeature>();
        try {
            conn = dbcManager.getConnection(poolName);
            conn.setAutoCommit(Boolean.FALSE);
            MongoConnection mc = this.getConnection(conn);
            DBCollection coll = mc.getDB().getCollection(this.tableName);
            for (IFeature feature : features) {
                // 若矢量要素为空则返回空或矢量要素不复合结构要求则返回空
                if (null == feature || !checkFeatureAttribute((BaseFeature) feature)) {
                    continue;
                }
                GeoGeometry geometry = feature.getGeometry();
                if (null == geometry) { // 若插入的空间几何对象为空则返回空
                    continue;
                }
                AttributeInfo attrInfo = feature.getAttributeInfo();
                AttributeValue[] attrValues = feature.getAttributes();
                // 实际拼接sql用到的属性名称
                // List<String> reqAttrName = new ArrayList<String>();
                // 实际插入到数据库中的字段值
                // List<AttributeValue> reqAttrValue = new
                // ArrayList<AttributeValue>();
                // 字段的数据类型
                // List<Integer> attrType = new ArrayList<Integer>();

                List<AttributeItem> l = attrInfo.getAttributeItems();
                BasicDBObject query = new BasicDBObject();

                // 获取待插入id
                Integer nextOID = getNextOID();
                // 构建一个新的OID·~
                long oid = GUID64Utils.randomGUID64();
                if (nextOID != null){
                    oid = (long) nextOID;
                }
                query.put("_id", oid);

                for (int i = 0, num = attrInfo.getAttributeNumber(); i < num; i++) {
                    AttributeValue attrValue = attrValues[i];
                    AttributeItem item = l.get(i);
                    String key = item.getName();
                    query.put(key, attrValue);
                    if (null != attrValue) {
                        AttributeValue value = attrValue;
                        switch (item.getType()) {
                            case Constants.TYPE_BOOLEAN:
                                String s = value.getBoolean() ? "T" : "F";
                                query.put(key, s);
                                break;
                            case Constants.TYPE_BYTE:
                                query.put(key, value.getByte());
                                break;
                            case Constants.TYPE_CHAR:
                            case Constants.TYPE_STRING:
                                query.put(key, value.getString());
                                break;
                            case Constants.TYPE_DATE:
                            case Constants.TYPE_TIMESTAMP:
                            case Constants.TYPE_TIME:
                                query.put(key, new Timestamp(value.getLong()));
                                break;
                            case Constants.TYPE_DOUBLE:
                                query.put(key, value.getDouble());
                                break;
                            case Constants.TYPE_FLOAT:
                                query.put(key, value.getFloat());
                                break;
                            case Constants.TYPE_SHORT:
                                query.put(key, value.getShort());
                                break;
                            case Constants.TYPE_INTEGER:
                                query.put(key, value.getInt());
                                break;
                            case Constants.TYPE_LONG:
                                query.put(key, value.getLong());
                                break;
                            case Constants.TYPE_BLOB:
                                query.put(key, (Blob) null);
                                break;
                            default:
                                break;
                        }
                    }
                }

                byte[] bytes = writer.write(geometry);
                GeoGeometry g = geometry.getEnvelope();
                /* 做一次仿射变换·~ */
                if (_change) {
                    double[][] xy = g.getCoordinates();
                    double[][] _xy = new double[xy.length][2];
                    for (int i = 0; i < xy.length; i++) {
                        // 如果是新数据，使用新的仿射方法
                        if ("eSimpleFeature".equals(featureType)) {
                            double[] tmp_xy = this.directAffine(xy[i][0], xy[i][1]);
                            _xy[i] = tmp_xy;
                        } else {
                            double tmp_x = this.coordinateToAffine(xy[i][0], true, false);
                            double tmp_y = this.coordinateToAffine(xy[i][1], false, true);
                            _xy[i] = new double[]{tmp_x, tmp_y};
                        }
                    }
                    GeoGeometryFactory fac = new GeoGeometryFactory();
                    g = fac.createMultiPoint(_xy).getEnvelope();
                }

                BasicDBObject obj_MBR = new GeometryParser().buildMBR(g);

                Binary b = new Binary(bytes);
                query.put("Geometry", b);
                query.put("MBR", obj_MBR);

                feature.setOID(oid);
                list.add(feature);
                // obj_list.add(query);
                coll.insert(query);
            }
            conn.commit();
            conn.setAutoCommit(Boolean.TRUE);
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_INSTER_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
        return list;
    }

    /**
     * 获取下一条矢量数据的oid
     * @return 将要插入矢量的oid
     */
    public Integer getNextOID(){
        Connection conn = null;
        MongoConnection mc = null;
        // 待返回的_id字段
        Integer oid = null;

        try {
            conn = dbcManager.getConnection(poolName);
            mc = this.getConnection(conn);
            // 查询元表是否有此数据表自增字段
            DBCollection spatialObjectClasses = mc.getDB().getCollection("SPATIAL_OBJECT_CLASSES");
            // 获取此表是否在geoglobe元表中
            BasicDBObject find = new BasicDBObject();
            // 过滤条件
            find.append("Name", this.dataName);
            BasicDBObject update = new BasicDBObject();
            DBObject inc = new BasicDBObject();
            // 自增字段
            inc.put("NextOID",1);
            update.append("$inc", inc);
            // 如果能够查询到那么属于geoglobe元表
            DBObject geoglobeTable = spatialObjectClasses.findAndModify(find, update);
            // 查询不到就不需要考虑OID自增问题
            if (geoglobeTable != null) {
                // 如果是geoglobe元表，findAndModify操作是初始化NextOID操作
                if (geoglobeTable.get("NextOID") == null) {
                    geoglobeTable = spatialObjectClasses.findAndModify(find, update);
                    oid = (int) geoglobeTable.get("NextOID");
                } else {
                    oid = (int) geoglobeTable.get("NextOID");
                }
            }
        } catch (Exception e){
            log.error(e.getMessage(), e.getCause());
        } finally {
            if (mc != null) {
                try {
                    mc.close();
                } catch (SQLException e) {
                    log.error(e.getMessage(), e.getCause());
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    log.error(e.getMessage(), e.getCause());
                }
            }
        }
        return oid;
    }

    /**
     * 更新一个要素
     *
     * @param feature 要素对象
     * @return 更新成功的要素对象
     */
    @Override
    public IFeature updateFeature(IFeature feature) throws DataSetException {
        // 若矢量要素为空则返回空或矢量要素不复合结构要求则返回空
        if (null == feature || !checkFeatureAttribute((BaseFeature) feature)) {
            return null;
        }

        GeoGeometry geometry = feature.getGeometry();
        AttributeInfo attrInfo = feature.getAttributeInfo();
        AttributeValue[] attrValues = feature.getAttributes();
        // 实际拼接sql用到的属性名称
        List<String> reqAttrName = new ArrayList<String>();
        // 实际插入到数据库中的字段值
        List<AttributeValue> reqAttrValue = new ArrayList<AttributeValue>();
        // 字段的数据类型
        List<Integer> attrType = new ArrayList<Integer>();
        for (int i = 0, num = attrInfo.getAttributeNumber(); i < num; i++) {
            AttributeValue attrValue = attrValues[i];
            if (null != attrValue) {
                reqAttrName.add(attrInfo.get(i).getName());
                reqAttrValue.add(attrValue);
                attrType.add(attrInfo.get(i).getType());
            }
        }

        String sql = spliceCRUDSql(1, reqAttrName, geometry);
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = dbcManager.getConnection(poolName);
            // OraWriter oraWriter = new OraWriter(conn);
            ps = conn.prepareStatement(sql);
            int k = 1;
            byte[] bytes = null;
            if (null != geometry) {
                bytes = writer.write(geometry);
                ps.setObject(1, bytes);
                k = 2;
            }

            for (int j = 0, size = reqAttrName.size(); j < size; j++, k++) {
                AttributeValue value = reqAttrValue.get(j);
                switch (attrType.get(j)) {
                    case Constants.TYPE_BOOLEAN:
                        String s = value.getBoolean() ? "T" : "F";
                        ps.setString(k, s);
                        break;
                    case Constants.TYPE_BYTE:
                        ps.setByte(k, value.getByte());
                        break;
                    case Constants.TYPE_CHAR:
                    case Constants.TYPE_STRING:
                        ps.setString(k, value.getString());
                        break;
                    case Constants.TYPE_DATE:
                    case Constants.TYPE_TIMESTAMP:
                    case Constants.TYPE_TIME:
                        ps.setTimestamp(k, new Timestamp(value.getLong()));
                        break;
                    case Constants.TYPE_DOUBLE:
                    case Constants.TYPE_FLOAT:
                        ps.setDouble(k, value.getDouble());
                        break;
                    case Constants.TYPE_SHORT:
                        ps.setShort(k, value.getShort());
                        break;
                    case Constants.TYPE_INTEGER:
                        ps.setInt(k, value.getInt());
                        break;
                    case Constants.TYPE_LONG:
                        ps.setLong(k, value.getLong());
                        break;
                    case Constants.TYPE_BLOB:
                        ps.setBlob(k, (Blob) null);
                        break;
                    default:
                        break;
                }
            }

            ps.setLong(k, feature.getOID());
            ps.execute();

            long oid = feature.getOID();
            MongoConnection mc = this.getConnection(conn);
            DBCollection coll = mc.getDB().getCollection(this.tableName);
            BasicDBObject query = new BasicDBObject();
            query.put("_id", oid);
            DBObject o = coll.findOne(query);

            GeoGeometry g = geometry.getEnvelope();
            /* 做一次仿射变换·~ */
            if (_change) {
                double[][] xy = g.getCoordinates();
                double[][] _xy = new double[xy.length][2];
                for (int i = 0; i < xy.length; i++) {
                    // 如果是新数据，使用新的仿射方法
                    if ("eSimpleFeature".equals(featureType)) {
                        double[] tmp_xy = this.directAffine(xy[i][0], xy[i][1]);
                        _xy[i] = tmp_xy;
                    } else {
                        double tmp_x = this.coordinateToAffine(xy[i][0], true, false);
                        double tmp_y = this.coordinateToAffine(xy[i][1], false, true);
                        _xy[i] = new double[]{tmp_x, tmp_y};
                    }
                }
                GeoGeometryFactory fac = new GeoGeometryFactory();
                g = fac.createMultiPoint(_xy).getEnvelope();
            }
            BasicDBObject obj_MBR = new GeometryParser().buildMBR(g);

            if (null != bytes) {
                o.put("Geometry", new Binary(bytes));
            }
            o.put("MBR", obj_MBR);
            coll.update(query, o);
            return feature;
        } catch (SQLException e) {
            log.error(e.getMessage(), e.getCause());
            Object[] orgs = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_UPDATE_FAILURE, orgs, e);
        } finally {
            // 关闭连接
            freeConn(null, null, ps, conn);
        }
    }

    /**
     * 更新一组要素
     *
     * @param features 要素集合
     * @return 更新成功的要素集合
     */
    @Override
    public List<IFeature> updateFeatures(List<IFeature> features)
            throws DataSetException {
        if (null == features) { // 若矢量要素集合为空则返回空
            return null;
        }

        Connection conn = null;
        List<IFeature> list = new ArrayList<IFeature>();
        try {
            conn = dbcManager.getConnection(poolName);
            conn.setAutoCommit(Boolean.FALSE);
            for (IFeature feature : features) {
                // 若矢量要素为空则返回空或矢量要素不复合结构要求则返回空
                if (null == feature || !checkFeatureAttribute((BaseFeature) feature)) {
                    continue;
                }
                GeoGeometry geometry = feature.getGeometry();
                AttributeInfo attrInfo = feature.getAttributeInfo();
                AttributeValue[] attrValues = feature.getAttributes();
                // 实际拼接sql用到的属性名称
                List<String> reqAttrName = new ArrayList<String>();
                // 实际插入到数据库中的字段值
                List<AttributeValue> reqAttrValue = new ArrayList<AttributeValue>();
                // 字段的数据类型
                List<Integer> attrType = new ArrayList<Integer>();
                for (int i = 0, num = attrInfo.getAttributeNumber(); i < num; i++) {
                    AttributeValue attrValue = attrValues[i];
                    if (null != attrValue) {
                        reqAttrName.add(attrInfo.get(i).getName());
                        reqAttrValue.add(attrValue);
                        attrType.add(attrInfo.get(i).getType());
                    }
                }

                String sql = spliceCRUDSql(1, reqAttrName, geometry);
                // OraWriter oraWriter = new OraWriter(conn);
                PreparedStatement ps = conn.prepareStatement(sql);
                int k = 1;
                byte[] bytes = null;
                if (null != geometry) {
                    bytes = writer.write(geometry);
                    ps.setObject(1, bytes);
                    k = 2;
                }

                for (int j = 0, size = reqAttrName.size(); j < size; j++, k++) {
                    AttributeValue value = reqAttrValue.get(j);
                    switch (attrType.get(j)) {
                        case Constants.TYPE_BOOLEAN:
                            String s = value.getBoolean() ? "T" : "F";
                            ps.setString(k, s);
                            break;
                        case Constants.TYPE_BYTE:
                            ps.setByte(k, value.getByte());
                            break;
                        case Constants.TYPE_CHAR:
                        case Constants.TYPE_STRING:
                            ps.setString(k, value.getString());
                            break;
                        case Constants.TYPE_DATE:
                        case Constants.TYPE_TIMESTAMP:
                        case Constants.TYPE_TIME:
                            ps.setTimestamp(k, new Timestamp(value.getLong()));
                            break;
                        case Constants.TYPE_DOUBLE:
                        case Constants.TYPE_FLOAT:
                            ps.setDouble(k, value.getDouble());
                            break;
                        case Constants.TYPE_SHORT:
                            ps.setShort(k, value.getShort());
                            break;
                        case Constants.TYPE_INTEGER:
                            ps.setInt(k, value.getInt());
                            break;
                        case Constants.TYPE_LONG:
                            ps.setLong(k, value.getLong());
                            break;
                        case Constants.TYPE_BLOB:
                            ps.setBlob(k, (Blob) null);
                            break;
                        default:
                            break;
                    }
                }

                ps.setLong(k, feature.getOID());
                ps.execute();
                ps.close();

                long oid = feature.getOID();
                MongoConnection mc = this.getConnection(conn);
                DBCollection coll = mc.getDB().getCollection(this.tableName);
                BasicDBObject query = new BasicDBObject();
                query.put("_id", oid);
                DBObject o = coll.findOne(query);

                GeoGeometry g = geometry.getEnvelope();
                /* 做一次仿射变换·~ */
                if (_change) {
                    double[][] xy = g.getCoordinates();
                    double[][] _xy = new double[xy.length][2];
                    for (int i = 0; i < xy.length; i++) {
                        // 如果是新数据，使用新的仿射方法
                        if ("eSimpleFeature".equals(featureType)) {
                            double[] tmp_xy = this.directAffine(xy[i][0], xy[i][1]);
                            _xy[i] = tmp_xy;
                        } else {
                            double tmp_x = this.coordinateToAffine(xy[i][0], true, false);
                            double tmp_y = this.coordinateToAffine(xy[i][1], false, true);
                            _xy[i] = new double[]{tmp_x, tmp_y};
                        }
                    }
                    GeoGeometryFactory fac = new GeoGeometryFactory();
                    g = fac.createMultiPoint(_xy).getEnvelope();
                }
                BasicDBObject obj_MBR = new GeometryParser().buildMBR(g);

                if (null != bytes) {
                    o.put("Geometry", new Binary(bytes));
                }
                o.put("MBR", obj_MBR);
                coll.update(query, o);
                list.add(feature);
            }
            conn.commit();
            conn.setAutoCommit(Boolean.TRUE);
        } catch (SQLException e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_UPDATE_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
        return list;
    }

    /**
     * 删除一个要素
     *
     * @param feature 要素对象
     * @return 删除成功的要素对象
     */
    @Override
    public IFeature deleteFeature(IFeature feature) throws DataSetException {
        if (null == feature) { // 若矢量要素为空则抛出异常
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.FEATURE_NULL);
        }

        Connection conn = null;
        PreparedStatement ps = null;
        String sql = spliceCRUDSql(2, null, null);
        try {
            conn = dbcManager.getConnection(poolName);
            ps = conn.prepareStatement(sql);
            ps.setLong(1, feature.getOID());
            ps.executeUpdate();
            return feature;
        } catch (SQLException e) {
            log.error(e.getMessage(), e.getCause());
            Object[] orgs = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_DELETE_FAILURE, orgs, e);
        } finally {
            // 关闭连接
            freeConn(null, null, ps, conn);
        }
    }

    /**
     * 删除一组要素
     * 2023/3/28 jiazixu  由于mongo-unityjdbc不支持batch操作,具体原因查看有关mongo-unityjdbc-20181121.jar Statement相关内容
     * 修改为遍历单个删除; 以前为事务批量删除
     *
     * @param features 要素数组
     * @return 删除成功的数量
     */
    @Override
    public List<IFeature> deleteFeatures(List<IFeature> features)
            throws DataSetException {
        if (null == features||features.size()==0) { // 若矢量要素为空则返回空
            return features;
        }
        List<IFeature> list = new ArrayList<IFeature>();
        // 修复bug26405, 由以前批量修改为单个删除
        for (IFeature feature : features) {
            IFeature delete = deleteFeature(feature);
            list.add(delete);
        }

        return list;
    }

    /**
     * 根据指定的OID删除一个要素
     *
     * @param oid 要素的OID
     */
    @Override
    public void deleteFeature(long oid) throws DataSetException {
        Connection conn = null;
        try {
            conn = dbcManager.getConnection(poolName);
            MongoConnection mc = this.getConnection(conn);
            DBCollection coll = mc.getDB().getCollection(this.tableName);
            BasicDBObject query = new BasicDBObject();
            query.put("_id", oid);
            DBObject o = coll.findOne(query);
            if (o == null) {
                /* 要素不存在·~ */
                log.debug("_id为" + oid + "的要素不存在·~ ");
                throw new DataSetException(MongoVectorDataSet.class,
                        TextCodesConst.DATASET_DELETE_FAILURE);
            }
            coll.remove(o);
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_DELETE_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
    }

    /**
     * 根据指定的OID删除一组要素
     *
     * @param oids 要素的OID数组
     */
    @Override
    public void deleteFeatures(long... oids) throws DataSetException {
        for (long oid : oids) {
            deleteFeature(oid);
        }
    }

    /**
     * 删除全部要素
     */
    @Override
    public void deleteAllFeatures() throws DataSetException {
        String sql = "DELETE FROM " + tableName;
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = dbcManager.getConnection(poolName);
            conn.setAutoCommit(Boolean.FALSE);
            ps = conn.prepareStatement(sql);
            ps.executeUpdate();
            conn.commit();
            conn.setAutoCommit(Boolean.TRUE);
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            Object[] args = {sql};
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_DELETE_FAILURE, args, e);
        } finally {
            // 关闭连接
            freeConn(null, null, ps, conn);
        }
    }

    /**
     * 添加一个属性列
     *
     * @param att 属性列对象
     * @return 添加成功返回true，否则返回false
     */
    @Override
    public boolean addAttributeItem(AttributeItem att) throws DataSetException {
        int attType = att.getType();
        // 列数据库对应类型
        String[] columnCharacters = getColumnTypeCharacter(att);
        String columnCharacter = columnCharacters[0];
        String columnDefValue = columnCharacters[1];
        if (null == columnCharacter || "".equals(columnCharacter)) {
            // 列数据库类型无法匹配错误
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_COLUMN_NOMATCH_ERROR,
                    new String[]{String.valueOf(attType)});
        }

        boolean result = false;
        // 是否可以为空
        String isNullable = att.isNullable() ? "null" : "not null";
        // sql
        String sql = getAlterTableSql(tableName,att.getName().toUpperCase(),columnCharacter,columnDefValue,isNullable);
        Connection conn = null;
        PreparedStatement stmt = null;
        try {
            conn = dbcManager.getConnection(poolName);
            stmt = conn.prepareStatement(sql);
            // 执行结果
            result = stmt.executeUpdate() >= 1 ? true : false;
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_ADD_COLUMN_ERROR,
                    new String[]{sql}, e);
        } finally {
            // 关闭连接
            freeConn(null, stmt, null, conn);
        }
        return result;
    }
    static String getAlterTableSql(String tableName,String Name,String columnCharacter,String columnDefValue,String isNullable){
        return "ALTER TABLE " + tableName + " ADD " + Name + " " + columnCharacter + " " + columnDefValue + " " + isNullable;
    }

    /**
     * 更新一个属性列
     *
     * @param att 属性列对象
     * @return 更新成功返回true，否则返回false
     */
    @Override
    public boolean updateAttributeItem(AttributeItem att)
            throws DataSetException {
        return false;
    }

    /**
     * 更新空间源数据
     *
     * @param envelope 空间几何外包矩形对象
     * @throws DataSetException
     */
    @Override
    public void updateSpatialMetaData(GeoEnvelope envelope)
            throws DataSetException {
        Connection conn = null;
        try {
            conn = dbcManager.getConnection(poolName);
            MongoConnection mc = this.getConnection(conn);
            DBCollection coll = mc.getDB().getCollection(
                    "SPATIAL_OBJECT_CLASSES");
            BasicDBObject query = new BasicDBObject();

            query.put("Name", this.dataName);
            DBObject dbo = coll.findOne(query);

            dbo.put("Extent",
                    new double[]{envelope.getMinX(), envelope.getMinY(),
                            envelope.getMaxX(), envelope.getMaxY()});
            WriteResult wr = coll.update(query, dbo);
            if (log.isDebugEnabled()) {
                log.debug(wr.toString());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_UPDATE_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
    }

    /**
     * 删除一个属性列
     *
     * @param name 属性列名称
     * @return 删除成功返回true，否则返回false
     */
    @Override
    public boolean deleteAttributeItem(String name) throws DataSetException {
        return false;
    }

    /**
     * 检查要素对象的属性字段与其属性信息是否一致，并根据当前数据的属性结构信息调整属性字段的顺序
     *
     * @param feature 待检查的检查要素对象
     * @return 矢量要素满足检查规则则返回“true”，否则返回“false”
     */
    private boolean checkFeatureAttribute(BaseFeature feature) {
        // 获取要素的属性信息和属性值
        AttributeInfo featureAttrInfo = feature.getAttributeInfo();
        AttributeValue[] featureAttrValue = feature.getAttributes();
        AttributeInfo attributeInfo = this.dataInfo.getAttributeInfo();
        if (null == featureAttrValue) {
            // 要素的属性值为空时，按照当前数据的属性结构为其构造属性值数组
            feature.setAttributeInfo(attributeInfo);
            featureAttrValue = new AttributeValue[attributeInfo
                    .getAttributeNumber()];
            feature.setAttributes(featureAttrValue);
            return true;
        } else {
            int attrValueNum = featureAttrValue.length;
            int attrNum = featureAttrInfo.getAttributeNumber();
            if (attrNum != attrValueNum) {
                // 要素对象本身的属性信息和属性值不匹配时，返回false
                return false;
            }

            // 当前数据的属性字段个数
            int dataAttrNum = attributeInfo.getAttributeNumber();
            AttributeValue[] attrValue = null;
            if (attrValueNum != dataAttrNum) {
                // 要素的属性值数组长度与当前数据的属性字段个数不匹配时，需要重新构造要素的属性值数组，并根据属性名称从原来的属性值数组中提取对应的属性值
                attrValue = new AttributeValue[dataAttrNum];
                for (int i = 0; i < dataAttrNum; i++) {
                    String dataAttrName = this.attributes.get(i);
                    for (int j = 0; j < attrValueNum; j++) {
                        if (dataAttrName.equalsIgnoreCase(featureAttrInfo
                                .getAttribute(j).getName())) {
                            // 根据属性名称进行匹配
                            attrValue[i] = featureAttrValue[j];
                            break;
                        }
                    }
                }
            } else {
                // 为了减少构造的属性值数组，尽量重复使用已有的属性值数组
                attrValue = featureAttrValue;
                for (int i = 0; i < dataAttrNum; i++) {
                    // 循环遍历当前数据的属性字段
                    String dataAttrName = this.attributes.get(i);
                    AttributeItem itemi = featureAttrInfo.getAttribute(i);
                    for (int j = i; j < attrValueNum; j++) {
                        // 循环遍历要素的属性字段
                        AttributeItem itemj = featureAttrInfo.getAttribute(j);
                        if (dataAttrName.equalsIgnoreCase(itemj.getName())) {
                            // 数据的属性字段名称与要素的属性字段名称一致时
                            if (i < j) {
                                // 数据的属性字段索引与要素的属性字段索引不同时，交换要素的属性字段和属性值
                                AttributeValue tmp = attrValue[i];
                                attrValue[i] = attrValue[j];
                                attrValue[j] = tmp;

                                featureAttrInfo.remove(i);
                                featureAttrInfo.remove(j);
                                featureAttrInfo.add(i, itemj);
                                featureAttrInfo.add(j, itemi);
                            }
                            break;
                        }
                    }
                }
            }
            feature.setAttributeInfo(attributeInfo);
            feature.setAttributes(attrValue);
            return true;
        }
    }

    /**
     * 拼接编辑的SQL语句
     *
     * @param type
     * @param attrNames
     * @param geometry
     * @return 编辑的SQL语句
     */
    private String spliceCRUDSql(int type, List<String> attrNames,
                                 GeoGeometry geometry) {
        StringBuffer sql = new StringBuffer();
        int attrnum = 0;
        switch (type) {
            case 0:
                attrnum = attrNames.size();
                sql.append("INSERT INTO ");
                sql.append(tableName);
                /* id, Geometry, MBR 是必须的·~ */
                sql.append(" (_id,Geometry,MBR");

                for (int i = 0; i < attrnum; i++) {
                    sql.append(", ");
                    // 20131225.在拼sql语句的过程中将要查询的属性字段名称加上双引号
                    sql.append("" + attrNames.get(i) + "");
                }

                sql.append(") VALUES(?,?,?");

                for (int i = 0; i < attrnum; i++) {
                    sql.append(",?");
                }

                sql.append(")");
                break;
            case 1:
                attrnum = attrNames.size();
                sql.append("UPDATE ");
                sql.append(tableName);
                sql.append(" SET ");
                if (null != geometry) {
                    sql.append("GEOMETRY");
                    sql.append("=?");
                }

                for (int i = 0; i < attrnum; i++) {
                    if (null != geometry || 0 != i) {
                        sql.append(", ");
                    }
                    sql.append("" + attrNames.get(i) + "");
                    sql.append("=?");
                }

                sql.append(" WHERE _id = ?");
                break;
            case 2:
                sql.append("DELETE FROM ");
                sql.append(tableName);
                sql.append(" WHERE _id = ?");
                break;
            default:
                break;
        }
        return sql.toString();
    }

    /**
     * 获取字段类型描述字符串
     *
     * @param att 字段详细描述
     * @return 字段类型描述字符串
     */
    private String[] getColumnTypeCharacter(AttributeItem att) {
        String columnType = "";
        String columnDef = "";
        int length = att.getLength();
        String defValue = att.getDefaultValue();
        switch (att.getType()) {
            case Types.DOUBLE:
                columnType = "DOUBLE";
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default " + defValue + " ";
                }
                break;
            case Types.FLOAT:
                columnType = "FLOAT";
                if (length != 0) {
                    columnType += "(" + String.valueOf(length) + ")";
                }
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default " + defValue + " ";
                }
                break;
            case Types.INTEGER:
                columnType = "INTEGER";
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default " + defValue + " ";
                }
                break;
            case Types.VARCHAR:
                columnType = "VARCHAR";
                if (length == 0) {
                    columnType += "(2048)";
                } else {
                    columnType += "(" + String.valueOf(length) + ")";
                }
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default '" + defValue + "' ";
                }
                break;
            case Types.BLOB:
                columnType = "BLOB";
                break;
            case Types.CHAR:
                columnType = "CHAR";
                if (length != 0) {
                    columnType += "(" + String.valueOf(length) + ")";
                }
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default '" + defValue + "' ";
                }
                break;
            case Types.DATE:
                columnType = "DATE";
                if (null != defValue && !"".equals(defValue)) {
                    columnDef = " default '" + defValue + "' ";
                }
                break;
        }
        return new String[]{columnType, columnDef};
    }

    /**
     * 关闭连接
     *
     * @param rs
     * @param stmt
     * @param ps
     * @param conn
     */
    private void freeConn(ResultSet rs, Statement stmt, PreparedStatement ps,
                          Connection conn) {
        if (null != rs) {
            try {
                rs.close();
            } catch (SQLException e) {
                log.error("数据连接对象关闭异常!", e);
            }
        }

        if (null != stmt) {
            try {
                stmt.close();
            } catch (SQLException e2) {
                log.error("数据连接对象关闭异常!", e2);
            }
        }

        if (null != ps) {
            try {
                ps.close();
            } catch (SQLException e3) {
                log.error("数据连接对象关闭异常!", e3);
            }
        }

        if (null != conn) {
            try {
                conn.close();
            } catch (SQLException e4) {
                log.error("数据连接对象关闭异常!", e4);
            }
        }
    }

    /**
     * 获取数据连接对象
     *
     * @param conn 数据连接对象
     * @return
     */
    private MongoConnection getConnection(Connection conn) {
        if (conn instanceof MongoConnection) {
            return (MongoConnection) conn;
        } else {
            if (conn instanceof DelegatingConnection) {
                DelegatingConnection dcon = (DelegatingConnection) conn;
                Connection o1 = dcon.getInnermostDelegate();
                if (o1 instanceof MongoConnection) {
                    return (MongoConnection) o1;
                }
            }
        }
        return null;
    }

    /**
     * 属性名称常量枚举
     */
    enum MetaKey {
        /**
         * 属性名称常量：数据集名称
         */
        Name,

        /**
         * 属性名称常量：数据集别名
         */
        AliasName,

        /**
         * 属性名称常量：编码类型
         */
        Endian,

        /**
         * 属性名称常量：EPSG号
         */
        EPSG,

        /**
         * 属性名称常量：空间参考
         */
        SpatialReference,

        /**
         * 属性名称常量：注记数据标识
         */
        FeatureType,

        /**
         * 属性名称常量：数据集的几何类型
         */
        GeometryType,

        /**
         * 属性名称常量：数据集的比例尺
         */
        Scale,

        /**
         * 属性名称常量：数据范围的最小X坐标
         */
        XMin,

        /**
         * 属性名称常量：数据范围的最大X坐标
         */
        XMax,

        /**
         * 属性名称常量：数据范围的最小Y坐标
         */
        YMin,

        /**
         * 属性名称常量：数据范围的最大Y坐标
         */
        YMax,

        /**
         * 属性名称常量：X方向容差
         */
        XTolerance,

        /**
         * 属性名称常量：Y方向容差
         */
        YTolerance;
    }

    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("\n");
        buf.append("========== The [MongoVectorDataSet] information =========="
                + "\n");
        buf.append("DataSourceInfo : " + this.dsInfo + "\n");
        buf.append("VectorDataSetInfo : " + this.dataInfo + "\n");
        buf.append("数据表名 ： " + this.tableName + "\n");
        buf
                .append("========================== END. ==========================");
        buf.append("\n");
        return buf.toString();
    }

    @Override
    public String getTableName() {
        // TODO Auto-generated method stub
        return this.tableName;
    }

    @Override
    public String getTableComment() {
        // TODO Auto-generated method stub
        return "";
    }

    @Override
    public void fastInsertFeatures(List<IFeature> features) throws DataSetException {
        if (null == features) { // 矢量要素集合为空则返回空
            return;
        }

        Connection conn = null;
        try {
            conn = dbcManager.getConnection(poolName);
            conn.setAutoCommit(Boolean.FALSE);
            MongoConnection mc = this.getConnection(conn);
            DBCollection collection = mc.getDB().getCollection(this.tableName);

            List<DBObject> dbObjList = new ArrayList<DBObject>();

            for (IFeature feature : features) {
                // 若矢量要素为空则返回空或矢量要素不复合结构要求则返回空
                if (null == feature || !checkFeatureAttribute((BaseFeature) feature)) {
                    continue;
                }

                GeoGeometry geometry = feature.getGeometry();
                if (null == geometry) { // 若插入的空间几何对象为空则返回空
                    continue;
                }
                AttributeInfo attrInfo = feature.getAttributeInfo();
                AttributeValue[] attrValues = feature.getAttributes();
                List<AttributeItem> l = attrInfo.getAttributeItems();
                BasicDBObject dbObj = new BasicDBObject();

                // 获取待插入id
                Integer nextOID = getNextOID();
                // 构建一个新的OID·~
                long oid = GUID64Utils.randomGUID64();
                if (nextOID != null){
                    oid = (long) nextOID;
                }
                dbObj.put("_id", oid);

                for (int i = 0, num = attrInfo.getAttributeNumber(); i < num; i++) {
                    AttributeValue attrValue = attrValues[i];
                    AttributeItem item = l.get(i);
                    String key = item.getName();
                    dbObj.put(key, attrValue);
                    if (null != attrValue) {
                        AttributeValue value = attrValue;
                        switch (item.getType()) {
                            case Constants.TYPE_BOOLEAN:
                                String s = value.getBoolean() ? "T" : "F";
                                dbObj.put(key, s);
                                break;
                            case Constants.TYPE_BYTE:
                                dbObj.put(key, value.getByte());
                                break;
                            case Constants.TYPE_CHAR:
                            case Constants.TYPE_STRING:
                                dbObj.put(key, value.getString());
                                break;
                            case Constants.TYPE_DATE:
                            case Constants.TYPE_TIMESTAMP:
                            case Constants.TYPE_TIME:
                                dbObj.put(key, new Timestamp(value.getLong()));
                                break;
                            case Constants.TYPE_DOUBLE:
                                dbObj.put(key, value.getDouble());
                                break;
                            case Constants.TYPE_FLOAT:
                                dbObj.put(key, value.getFloat());
                                break;
                            case Constants.TYPE_SHORT:
                                dbObj.put(key, value.getShort());
                                break;
                            case Constants.TYPE_INTEGER:
                                dbObj.put(key, value.getInt());
                                break;
                            case Constants.TYPE_LONG:
                                dbObj.put(key, value.getLong());
                                break;
                            case Constants.TYPE_BLOB:
                                dbObj.put(key, (Blob) null);
                                break;
                            default:
                                break;
                        }
                    }
                }

                byte[] bytes = writer.write(geometry);
                GeoGeometry g = geometry.getEnvelope();
                /* 做一次仿射变换·~ */
                if (_change) {
                    double[][] xy = g.getCoordinates();
                    double[][] _xy = new double[xy.length][2];
                    for (int i = 0; i < xy.length; i++) {
                        // 如果是新数据，使用新的仿射方法
                        if ("eSimpleFeature".equals(featureType)) {
                            double[] tmp_xy = this.directAffine(xy[i][0], xy[i][1]);
                            _xy[i] = tmp_xy;
                        } else {
                            double tmp_x = this.coordinateToAffine(xy[i][0], true, false);
                            double tmp_y = this.coordinateToAffine(xy[i][1], false, true);
                            _xy[i] = new double[]{tmp_x, tmp_y};
                        }
                    }
                    GeoGeometryFactory fac = new GeoGeometryFactory();
                    g = fac.createMultiPoint(_xy).getEnvelope();
                }

                BasicDBObject obj_MBR = new GeometryParser().buildMBR(g);

                Binary b = new Binary(bytes);
                dbObj.put("Geometry", b);
                dbObj.put("MBR", obj_MBR);

                dbObjList.add(dbObj);
            }
            collection.insert(dbObjList);
            dbObjList.clear();

            conn.commit();
            conn.setAutoCommit(Boolean.TRUE);
        } catch (Exception e) {
            log.error(e.getMessage(), e.getCause());
            throw new DataSetException(MongoVectorDataSet.class,
                    TextCodesConst.DATASET_INSTER_FAILURE, e);
        } finally {
            // 关闭连接
            freeConn(null, null, null, conn);
        }
    }

    @Override
    public void fastMergeFeatures(List<IFeature> features, Connection conn) throws DataSetException {
        // TODO
    }

    public String getWtfsDisplayField() {
        return this.wtfsDisplayField;
    }
}